当项目大规模使用 Docker 时,容器通信的问题也就产生了。要解决容器通信问题,必须先了解很多关于网络的知识。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker 同样有着很多不完善的地方,网络方面就是 Docker 比较薄弱的部分。因此,我们有必要深入了解 Docker 的网络知识,以满足更高的网络需求。

网络类型

默认网络

  安装 Docker 以后,会默认创建三种网络,可以通过docker network ls查看。在学习 Docker 网络之前,我们有必要先来了解一下这几种网络都是什么意思。

1
2
3
4
5
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
36570517f5be bridge bridge local
f6d43768bd2e host host local
5f321de0ff22 none null local
  • bridge:为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,默认为该模式

    • 在该模式中,Docker 守护进程创建了一个虚拟以太网桥docker0 ,新建的容器会自动桥接到这个接口,附加在其上的任何网卡之间都能自动转发数据包。

    • 默认情况下,守护进程会创建一对对等虚拟设备接口veth pair ,将其中一个接口设置为容器的eth0接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似vethxxx 这样的名字命名,从而将宿主机上的所有容器都连接到这个内部网络上。

      image.png

      Docker 桥接网络架构

      image.png

      Docker 容器网卡配置

      image.png

      Docker 外接网卡
    • 通过以上的比较可以发现,证实了之前所说的:守护进程会创建一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的eth0接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似vethxxx 这样的名字命名。同时,守护进程还会从网桥docker0 的私有地址空间中分配一个IP地址和子网给该容器,并设置docker0的IP地址为容器的默认网关。也可以安装yum install -y bridge-utils 以后,通过brctl show 命令查看网桥信息。

    • 通过docker network inspect bridge 查看所有bridge网络模式下的容器,在Container节点中可以看到容器名称。

      image.png

    • 关于bridge网络模式的使用,只需要在创建容器时通过参数–net bridge或者–network bridge指定即可,当然这也是创建容器默认使用的网络模式,也就是说这个参数是可以省略的。

  • host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

    • 采用host网络模式的Docker Container,可以直接使用宿主机的IP地址与外界进行通信,若宿主机的eth0是一个公有IP,那么容器也拥有这个公有IP。容器内服务的端口也可以使用宿主机的端口,无需进行NAT转换。
    • host网络模式可以让容器共享宿主机网络栈,好处是外部主机与主机直接通信,但是容器的网络缺少隔离。image.png
    • host网络模式需要在创建容器时通过参数 –net host 或者 –network host指定;
1
2
3
$ docker run -id --name python01 --network host mypython3
6e9dc73db9258702d9a79c072b87fa65fd0f2b9b8f82a9d3a3f32b35376977bb
$ docker exec -it python01 bash

image.png

  • none:容器有独立的network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等。
  • container:新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定容器共享IP、端口范围等。
    • 处于这个模式下的Docker容器会共享一个网络栈,简单来讲就是两个容器共用一张网卡,这样两个容器之间可以使用localhost高效快速通信。image.png
    • container网络模式是Docker中一种较为特别的网络模式。在创建容器时通过参数 –net container:已运行的容器名称|ID 或者 –network container:已运行的容器名称|ID指定。
1
2
3
4
5
6
7
$ docker run -id --name python01 --net bridge mypython3
4fc118f49205a05df5fb2c6c82ba8bb730b9f21128ad8143de86315711d780b8
# 创建一个使用bridge模式的容器1

$ docker run -id --name python02 --net container:python01 mypython3
37f4a3ec4f7fce5a0bdd6b6630cd6fd5688303479013e3031088def0f2190076
# 创建一个使用container网卡模式的容器2.使用的是容器1的网卡

image.png

自定义网络

  虽然 Docker 提供的默认网络使用比较简单,但是为了保证各容器中应用的安全性,在实际开发中更推荐使用自定义的网络进行容器管理,以及启用容器名称到 IP 地址的自动 DNS 解析。注意在 bridge 的网卡模式下,IP 不固定!关闭容器 IP 地址就会被释放,启动的时候再获取 IP。
  从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称进行通信。方法很简单,只要在创建容器时使用–name 为容器命名即可。但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 查看network帮助信息
$ docker network --help
Usage: docker network COMMAND
Manage networks

Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks

# 步骤一:通过docker network create命令可以创建自定义网络模式,命令提示如下:
$ docker network create lmb_network
b68a11373c4bf1b0107fd21b8135ecb7f3cd3ded4acc10f2fcbfd2b16dc0532e
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
36570517f5be bridge bridge local
f6d43768bd2e host host local
b68a11373c4b lmb_network bridge local
5f321de0ff22 none null local

# 步骤二:使用lmb_network
$ docker run -id --name python01 --net lmb_network mypython3
$ docker run -id --name python02 --net lmb_network mypython3

image.png